package com.bayleaf.web.voGen;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import com.bayleaf.common.StringUtil;
import com.bayleaf.core.BayleafServlet;
import com.bayleaf.core.Model;

@WebServlet(name = "voGen", urlPatterns = { "/voGen" }, initParams = {
		@WebInitParam(name = "title", value = "VO Generator"),
		@WebInitParam(name = "jsp", value = "/voGen/VoGen") })
public class VoGenServlet extends BayleafServlet {
	
	private static final String LineSep = System.getProperty("line.separator");
	
	//전역 설정(그러나 없애고 싶다)
	Map<String, String> con_options;
	
	@Override
	public String process(Model model) throws Exception {
		System.out.println("Concrete process method :" + model.toString());
		/**
		 * 모델에 넘어온 각 값들을 받음
		 */
		String col_input = model.getString("col_input");
		String type_input = model.getString("type_input");
		String cmt_input = model.getString("cmt_input");
		String nullable_input = model.getString("nullable_input");
		
		con_options = new HashMap<String, String>();
		
		con_options.put("numberType", model.getParameter("numberType"));
		con_options.put("dateType", model.getParameter("dateType"));
		con_options.put("validation", model.getParameter("validation")); 
		con_options.put("trim", model.getParameter("trim")); 
		
		String col_fields[] = StringUtil.strTokenizer(col_input);
		String type_fields[] = StringUtil.strTokenizer(type_input);
		String cmt_fields[] = StringUtil.strTokenizer(cmt_input);
		String nullable_fields[] = StringUtil.strTokenizer(nullable_input);

//		System.out.println(convert_type_date + ":"+convert_type_number + ":"+validation_option);
		
		//vo 의 구성요소들을 만든다.
		StringBuilder resultVar = genVariablesComments(col_fields, type_fields,
				cmt_fields, nullable_fields);
		StringBuilder resultGetterSetter = genGetterSetter(col_fields,
				type_fields);
		StringBuilder resultToString = genToString(col_fields);
		
		
		//값을 모델에 다시 세팅한다.
		model.setString("output",
				resultVar.toString() + resultGetterSetter.toString() + resultToString.toString()
				);

		return null;
	}
	
	/**
	 * 코멘트, 변수선언, /@valid 어노테이션
	 * @param col_fields
	 * @param type_fields
	 * @param cmt_fields
	 * @return
	 */
	private StringBuilder genVariablesComments(String[] col_fields,
			String[] type_fields, String[] cmt_fields, String[] nullable_fields) {
		StringBuilder resultVar = new StringBuilder();
		String nullable = null;
		String constraint = null;
		for (int i = 0; i < col_fields.length; i++) {
			
			//comments
			if (cmt_fields != null || "".equals(cmt_fields)) {
				if (i < cmt_fields.length) {
					resultVar.append(LineSep+"/**" + LineSep + "*" + cmt_fields[i]
							+ LineSep + "*/" + LineSep);
				} else {
					resultVar.append(LineSep+"/**" + LineSep + "* comment for " +col_fields[i] + LineSep + "*/"
							+ LineSep);
				}
			}
			//@valid annotation
			nullable = "NO".equals(nullable_fields[i].toUpperCase())?"@NotBlank":null;
			constraint = extractConstraint(type_fields[i]); 
			if(con_options.get("validation") != null ){
				resultVar.append(
						(nullable !=null?nullable+LineSep:"")
						+ (constraint!=null?constraint+LineSep:"")
						);
			}
			
			//variables
			resultVar.append(
					"private " + getType(type_fields[i]) + " "
					+ StringUtil.underScoreToCamelCase(col_fields[i]) + ";"
					+ LineSep);
			
		}
		resultVar.append(LineSep);
		return resultVar;
	}


	/**
	 * gen to string method
	 * @param col_fields
	 * @return
	 */
	private StringBuilder genToString(String[] col_fields) {
		StringBuilder resultToString = new StringBuilder();
		resultToString.append( LineSep+ "@Override" + LineSep + "public String toString() {"+ LineSep
				+ "return \"VO:[\"+" );
		String sep = "";
		for (int i = 0; i < col_fields.length; i++) {
			
			if((i+1)!=col_fields.length){
				sep = "\", \"+";
			}else{
				sep = "";
			}
			resultToString.append(" \""+
					StringUtil.underScoreToCamelCase(col_fields[i])+"=\"+" +StringUtil.underScoreToCamelCase(col_fields[i])+"+"
					+sep
					);
		}
		resultToString.append("\"]\";"+LineSep + "}" + LineSep);
		return resultToString;
	}


	/**
	 * Generates getters and setters
	 * @param col_fields
	 * @param type_fields
	 * @return
	 */
	private StringBuilder genGetterSetter(String[] col_fields,
			String[] type_fields) {
		StringBuilder resultGetterSetter = new StringBuilder();
		// gen getter and setter
		for (int i = 0; i < col_fields.length; i++) {
			resultGetterSetter.append("public " + getType(type_fields[i])
					+ " get" + getModifiedCamelCase(col_fields[i]) + "(){"
					+ LineSep + "return "
					+ StringUtil.underScoreToCamelCase(col_fields[i]) + ";"
					+ LineSep + "}" + LineSep + LineSep

					+ "public void set" + getModifiedCamelCase(col_fields[i])
					+ "("+getType(type_fields[i]) + " "+StringUtil.underScoreToCamelCase(col_fields[i]) +"){" + LineSep + "this."
					+ StringUtil.underScoreToCamelCase(col_fields[i]) + "="
					+ StringUtil.underScoreToCamelCase(col_fields[i])
					//String 인 경우 trim붙인다.
					+	((getType(type_fields[i]).equals("String") && con_options.get("trim") != null)?	".trim()":"")+ ";"
					+ LineSep + "}" + LineSep);
		}
		return resultGetterSetter;
	}



	
	/**
	 * type convert
	 * @param str
	 * @return
	 */
	private String getType(String str) {
		if (str.contains("NUMBER")) {
			return con_options.get("numberType");
		} else if (str.contains("DATE")) {
			return con_options.get("dateType");
		} else { //char, varcahr
			return "String";
		}
	}
	
	private String extractConstraint(String str){
		//어거지 스트링 조작.
		if(str.contains("VARCHAR") || str.contains("CHAR")){
			
			int startIdx = str.indexOf('(');
			int lastIdx = str.lastIndexOf(')');
			
			String retStr = "@ByteSize(min=0,max=";
			
			for(int i=startIdx; i < lastIdx; i++){
				if(Character.isDigit(str.charAt(i))){
					retStr += str.charAt(i);
				}
			}
			return retStr + ")";
		}else{
			return null;
		}
	}

	/**
	 * camel case converting wrapper
	 * @param str
	 * @return
	 */
	public String getModifiedCamelCase(String str) {
		String var = StringUtil.underScoreToCamelCase(str);
		return (var.charAt(0) + "").toUpperCase()
				+ var.substring(1, var.length());

	}



	/**
	 * 카멜케이스 형식의 스트링을 언더바 구분으로 바꿈
	 * 
	 * @param camelCaseStr
	 * @return underScoreResult
	 */
	public static String camelCaseToUnderScore(String camelCaseStr) {
		return StringUtil.camelCaseToUnderScore(camelCaseStr);
	}

	/**
	 * 언더바 형식의 스트링을 카멜케이스로 바꿈
	 * 
	 * @param underScore
	 * @return camelCaseResult
	 */
	public static String underScoreToCamelCase(String underScore) {
		return StringUtil.underScoreToCamelCase(underScore);
	}

}
